package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.DataInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description DeviceServiceImpl
 * @Author apeng
 * @Date 2024-10-30
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class DeviceServiceImpl implements DeviceService {


    private final StringRedisTemplate redisTemplate;

    private final AliIoTConfigProperties aliIoTConfigProperties;

    private final Client client;

    private final DeviceMapper deviceMapper;

    //将iot产品列表放入redis中
    @Override
    public void syncProductList() {
        //获得iot列表
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(10);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryProductListResponse response = null;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        //获取响应体，判断是否调用成功，失败抛出异常，结束程序
        if (!response.getBody().getSuccess()){
            log.error(response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        //获取响应体
        List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo
                = response.getBody().getData().getList().getProductInfo();
        //将响应体转成怕productVo
        List<ProductVo> productVos = productInfo.stream().map(product -> {
            ProductVo productVo = new ProductVo();
            productVo.setProductKey(product.getProductKey());
            productVo.setProductName(product.getProductName());
            return productVo;
        }).collect(Collectors.toList());
        //将对象存入redis中
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVos));

    }


    /**
     *查询所有产品列表
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        String json = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        if (StrUtil.isNotEmpty(json)){
            return JSONUtil.toList(json,ProductVo.class);
        }
        return null;
    }


    //注册设备
    @Override
    public ResponseResult<Void> registerDevice(DeviceDto deviceDto) {
        //1.查询数据库注册的设备英文名是否重复
        //根据设备英文名查询设备对应数量
       Long count = deviceMapper.findCountByProductName(deviceDto.getProductName());
        //数量大于0，说明已存在，抛出异常结束程序
        if (count>0){
            log.info("注册设备失败，设备名称重复");
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        //2.远程调用IOT注册设备RegisterDevice接口，并且获取生成的设备id
        //从deviceDto中获取注册设备请求对象
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        //注册设备请求对象封装IotInstanceId属性
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //远程调用注册设备接口获取返回RegisterDeviceResponse对象
        RegisterDeviceResponse response;
        try {
            response = client.registerDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //捕获远程调用可能发生的异常,抛出友好提示异常
        if (!response.getBody().getSuccess()) {
            //获取RegisterDeviceResponse对象返回数据success判断是否调用成功，失败抛出友好提示异常
            log.info("注册设备异常，异常原因，{}",response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //接口调用成功，获取生成的设备id（响应体data.IotId），封装到deviceDto
        String iotId = response.getBody().getData().getIotId();
        deviceDto.setIotId(iotId);
        //3.deviceDto转换为device对象
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        //4.补全产品的名字，远程调用查询产品QueryProduct接口
        //构建查询产品请求对象，封装属性ProductKey和IotInstanceId
        QueryProductRequest request1 = new QueryProductRequest();
        request1.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request1.setProductKey(device.getProductKey());
        //远程调用注册设备接口获取返回QueryProductResponse对象
        QueryProductResponse response1 = null;
        try {
            response1 = client.queryProduct(request1);
        } catch (Exception e) {
            //捕获远程调用可能发生的异常,抛出友好提示异常
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //获取QueryProductResponse对象返回数据success判断是否调用成功，失败抛出友好提示异常
        if (!response1.getBody().getSuccess()){
            log.info("查询产品请求对象，{}",response1.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //接口调用成功，获取产品名字（响应体data.ProductName），封装到device
        device.setProductName(response1.getBody().getData().getProductName());
        //5.判断设备位置绑定类型是否为随身设备，如果是设置物理班绑定类型（physicalLocationType）为-1
        if (DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal().equals(device.getLocationType())){
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //6.将设备保存到数据库
        //补全是否包含门禁，默认设置为0
        device.setHaveEntranceGuard(0);
        //调用mapper保存
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            //捕获异常，远程调用删除IOT设备接口（DeleteDevice）
            //构建查删除IOT设备请求对象，封装属性IotInstanceId和IotId
            DeleteDeviceRequest request2 = new DeleteDeviceRequest();
            request2.setIotId(device.getIotId());
            request2.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            //远程调用删除设备接口
            DeleteDeviceResponse response2;
            try {
                response2 = client.deleteDevice(request2);
            } catch (Exception ex) {
                //捕获删除设备远程接口调用发生异常（如果其企业中删除失败，会记录日志，通知管理员（邮件或手机短信））
                log.info("删除设备异常");

                throw new RuntimeException(ex);
            }
            //获取QDeleteDeviceResponse对象返回数据success判断是否调用成功，失败抛出友好提示异常（如果其企业中删除失败，会记录日志，通知管理员（邮件或手机短信））
            if (!response2.getBody().getSuccess()){
                log.info("删除设备异常，{}",response2.getBody().getErrorMessage());
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            //抛出异常结束，提示友好信息
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        return ResponseResult.success();
    }


    //分页查询
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        Page<DeviceVo> page = deviceMapper.pageQueryDevice(devicePageQueryDto);
        PageResponse<DeviceVo> pageResponse = PageResponse.of(page, DeviceVo.class);
        return pageResponse;
    }

    //查询设备详细信息
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {
        DeviceVo deviceVo = deviceMapper.queryDeviceDetail(request.getIotId());
        if (deviceVo == null){
            throw  new RuntimeException("不存在当前设备");
        }
        //构建请求
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response = null;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            log.info("获取IOT远程设备详情数据失败，失败原因,{}", e.getMessage());
        }
        if (!response.getBody().getSuccess()){
            log.info("获取IOT远程设备详情数据失败，失败原因,{}",response.getBody().getErrorMessage());
        }
        if (response.getBody().getSuccess()) {
            QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();
            BeanUtil.copyProperties(data,deviceVo, CopyOptions.create().ignoreNullValue());
        }
        return deviceVo;
    }

    //查询指定产品已发布物模型中的功能定义详情
    @Override
    public ResponseResult queryThingModelPublished(QueryThingModelPublishedRequest request) {

        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response = null;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            log.info("查询指定物模型的功能定义详情失败,{}",response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_SERVICE_DATA_ERROR);
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_SERVICE_DATA_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    //- 查询指定设备的物模型运行状态
    @Override
    public ResponseResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
       request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response = null;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            log.info("查询物模型运行状态失败，失败原因{}",response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }

    @Override
    public ResponseResult UpdateDevice(DeviceDto dto) {
        Device device1 = deviceMapper.selectByPrimaryKey(dto.getId());
        if (device1 == null){
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);
        }
        //先将阿里云中的数据更改
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        List list = new ArrayList();
        list.add(dto.getRegisterDeviceRequest());
        request.setDeviceNicknameInfo(list);
        BatchUpdateDeviceNicknameResponse response = null;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            log.info("修改设备失败，失败原因{}",response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        //再更改数据库中数据
        Device device = BeanUtil.toBean(dto, Device.class);
        if (DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal().equals(device.getLocationType())){
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }

        deviceMapper.updateByPrimaryKeySelective(device);
        return ResponseResult.success();
    }

    //删除设备
    @Override
    public ResponseResult deleteDevice(DeleteDeviceRequest request) {
        DeleteDeviceResponse response;
        try {
            response = client.deleteDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        if (!response.getBody().getSuccess()){
            log.info("删除设备失败原因：{}",response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        deviceMapper.deleteByIotId(request.getIotId());
        return ResponseResult.success();
    }
}
